# Currently an empty package to organize the different calculation methods
package Fangcheng::Calc;

use 5.006001;
use strict;
use warnings;
use vars qw( @ISA );

require Fangcheng;

@ISA = qw( Fangcheng );

# multiply an entire row by a number
sub multiplyRow {
	my ($self, $matrix, $row, $mult) = @_;
	for ( my $col = 1; $col <= $matrix->columns(); $col++ ) {
		my $val = $matrix->get( $row, $col );
		# eval() converts fraction string into a floating point value
		$val = eval($val);
		$val *= $mult;
		$matrix->set( $row, $col, $val );
	}
}

# reduce fraction if possible
sub simplifyFraction {
	my ($self, $frac) = @_;
	my ($num, $den);
	if ( not $frac =~ /(\d+)\s*\/\s*(\d+)/ ) {
		return( $frac );
	}
	$num = $1;
	$den = $2;
	my $gcf = $self->commonFactor( $num, $den );
	$num /= $gcf;
	$den /= $gcf;
	return( "$num / $den ");
}

# returns greatest common factor for two numbers
sub commonFactor {
	my ($self, $x, $y) = @_;
	while ( $y != 0 ) {
		( $x, $y ) = ( $y, $x % $y );
	}
	return( $x );
}

# converts all fractions to integers by finding common factor
sub convertFractionsToIntegers {
	my ($self, $matrix) = @_;
	for ( my $row = 1; $row <= $matrix->rows(); $row++ ) {
		for ( my $col = 1; $col <= $matrix->columns(); $col++ ) {
			my $val = $matrix->get( $row, $col );
			my $num = $val;
			my $den = 1;
			if ( $val =~ /(\d+)\/(\d+)/ ) {
				($num, $den) = ($1, $2);
				my $gcf = $self->commonFactor( $num, $den );
				$den /= $gcf;
				$self->multiplyRow( $matrix, $row, $den );
			}
		}
	}
}

### stage checking/storing routines 					 ###
### we only save which steps mark beginning of new stage ###

# stores info about steps and stages internally
sub _stageStore {
	my ($self, $href) = @_;
	my ($step, $stage) = %$href;
	if ( not defined $self->stages ) {
		$self->stages( [] );
	}
	$self->stages->[$stage] = $step;
}

sub _stageCheck {
	my ($self, $step) = @_;
	my $ret = 0;
	foreach my $storedStep ( @{ $self->stages } ) {
		if ( $step == $storedStep ) {
			$ret = 1;
			last;
		}
	}
	return( $ret );
}

# stores information about which steps mark a new stage of calculations
sub nextStage {
	my ($self, $step) = @_;
	my $stage = $self->stage;
	if ( not defined $stage ) {
		$self->stage(0);
		$stage = 0;
	}
	else {
		$self->stage( ++$stage );
	}
	$self->_stageStore( {$step => $stage} );
}

# checks if the given step is the beginning of a new calculation stage
# necessary for display modules so they know when to switch their output
sub isNextStage {
	my ($self, $step) = @_;
	my $ret = 0;
	if ( $self->_stageCheck($step) == 1 ) {
		$ret = 1;
	}
	
	return( $ret );
}

# returns the last step of calculation
sub lastStep {
	my ($self) = shift;
	my @stages = @{ $self->stages };
	return( pop @stages );
}

# return the first step for given stage
sub stageStep {
	my ($self, $stage) = @_;
	if ( $stage < 1 or $stage > 3 ) {
		return(0);
	}
	return( ${$self->stages}[$stage] );
}

# returns the stage for a given step
sub getStage {
	my ($self, $step) = @_;

	my $stageCurrent = 0;
	my $stage = 0;
	foreach my $stepStage ( @{ $self->stages } ) {
		if ( $step <= $stepStage ) {
			$stage = $stageCurrent;
			last;
		}
		$stageCurrent++;
	}
	return( $stage );
}
1;